
class Container<T extends object>{
  t!: T;
  constructor(t_: T) {
    this.t = t_
  }
  show() {
    console.log(this.t)
    return this.t
  }
}
let obj: object = { username: 'burt', age: 18 }
let c = new Container<object>(obj)
c.show()

type objtype = { username: string, age: number }
let obj2: objtype = { username: 'zhangj', age: 16 }
let c2 = new Container<objtype>(obj2)
c2.show()

class Customer {
  constructor(public name:string) {

  }
}

let cust = new Customer('yang')
let c3 = new Container<Customer>(cust)
c3.show()


// 比如我想获取username的类型
type objType = {
  username: string,
  age: number
}
type nameType = objType['username']



class ObjectImpl<T extends object, K extends keyof T>{
  object!:T
  key!:K
  constructor(object_: T, key_: K) {
    this.object = object_
    this.key = key_
  }
  getValue() {
    return this.object[this.key]
  }
  setValue(newValue: T[K]) {
    this.object[this.key] = newValue
  }
}

class Order {
  constructor(public name:string, public price:number, public phone:string) {

  }
}
let order = new Order('张三', 19999, '15171311521')
let objectImpl = new ObjectImpl<Order, 'phone'>(order, 'phone')
console.log(objectImpl.getValue()) // '15171311521'
objectImpl.setValue('10086') // 因为这时候objectImpl实例里面T[K]得到的是phone属性的类型为string，所以必须设置为string类型才对



// 泛型接口
interface List<T> {
  add(ele: T): void
  get(index: number): T
  size(): number
  remove(value: T): T
}
class LinkedList<T> implements List<T> {
  add(ele: T): void {
    throw new Error("Method not implemented.");
  }
  get(index: number): T {
    throw new Error("Method not implemented.");
  }
  size(): number {
    throw new Error("Method not implemented.");
  }
  remove(value: T): T {
    throw new Error("Method not implemented.");
  }
}


/** 泛型接口 + TS泛型约束 + 多态 组合应用
 * 多态体现在： 1. 父类对象变量可以接受任何它的子类对象
 * 2. 接口类型对象变量可以接受任何它的实现类的对象
 * **/
// 简单粗暴方式一：
class Vechile {
  constructor(public name:string, public pai:string, public price:number) {
    this.name = name
    this.pai = pai
    this.price = price
  }
  public calcPrice() {
    return this.price
  }
}
class Bus extends Vechile {
  
}
class Truck extends Vechile {
  
}
class Customer2 {
  // 计算价格
  public rentVechile(myVechileArray: Vechile[]) {
    let total = 0
    myVechileArray.forEach(item => {
      total += item.calcPrice()       
    })
    return total
  }
}
let vechileArray:Vechile[] = []
vechileArray[0] = new Bus('大巴', '京125AFF1', 5000)
vechileArray[1] = new Truck('大卡车', '京24GW4', 10000)
let cust2 = new Customer2()
cust2.rentVechile(vechileArray)

// 使用接口泛型处理方案二
class Customer3 {
  // 计算价格
  public rentVechile(myVechileArray: List<Vechile>) {

  }
}
let vechileArray3:List<Vechile> = new LinkedList<Vechile>()
vechileArray3.add(new Bus('大巴', '京125AFF1', 5000))
vechileArray3.add(new Truck('大卡车', '京24GW4', 10000))

// 使用接口泛型处理方案三
class Customer4 {
  // 计算价格
  public rent<T extends object>(list: List<T>) {
    let total = 0
    for(let i = 0; i < list.size(); i++) {
      let something = list.get(i)
      total += (something as any).calcPrice()
    }
    return total
  }
}
let vechileArray4:List<Vechile> = new LinkedList<Vechile>()
vechileArray4.add(new Bus('大巴', '京125AFF1', 5000))
vechileArray4.add(new Truck('大卡车', '京24GW4', 10000))
let cust4 = new Customer4()
cust4.rent<Vechile>(vechileArray4)

